class Cell:
    """
        Handles each cell's rendering/click response
    """
    def __init__(self, vg, x, y):
        self.x = x
        self.y = y
        self.state = 1
        self.element = document.createElementNS(vg.ns, "rect")
        self.element.setAttribute("x", self.x * 10)
        self.element.setAttribute("y", self.y * 10)
        self.element.setAttribute("width", 9)
        self.element.setAttribute("height", 9)
        self.element.addEventListener("click", self.toggle, false)
        self.toggle()
        vg.appendChild(self.element)

    def toggle(self):
        self.state = not(self.state)
        if self.state:
            self.element.setAttribute("fill", "#00ff00")
        else:
            self.element.setAttribute("fill", "#000000")

class Game:
    """
        Handles grid construction and game loop
        (offers simple interfacing for external control)
    """
    def __init__(self, vg, w, h):
        self.vg = vg
        self.w = w
        self.h = h
        self.cells = []
        self.interval = 0
        self.buildCallback = 0
        setTimeout(lambda x: self._build(), 100)

    def onBuild(self, callback):
        self.buildCallback = callback

    def _build(self):
        size = len(self.cells)
        if size < self.h:
            self.cells.append([])
            for x in xrange(self.w):
                self.cells[-1].append(Cell(self.vg, x, size))
            setTimeout(lambda x: self._build(), 50)
        elif self.buildCallback:
            self.buildCallback()

    def _neighbors(self, x, y):
        n = 0
        for yo in xrange(-1, 2):
            ny = y + yo
            if ny >= 0 and ny < self.h:
                for xo in xrange(-1, 2):
                    nx = x + xo
                    if (nx >= 0 and nx < self.w) and (yo or xo):
                        if self.cells[ny][nx].state:
                            n += 1
        return n

    def step(self):
        stack = []
        for y in xrange(self.h):
            for x in xrange(self.w):
                n = self._neighbors(x, y)
                if self.cells[y][x].state:
                    if n < 2 or n > 3:
                        stack.append(self.cells[y][x])
                else:
                    if n == 3:
                        stack.append(self.cells[y][x])
        stackLen = len(stack)
        if stackLen:
            for i in xrange(stackLen):
                stack[i].toggle()
        else:
            self.toggle()

    def toggle(self):
        if self.interval:
            clearInterval(self.interval)
            self.interval = 0
        else:
            self.interval = setInterval(lambda: self.step(), 100)

    def clear(self):
        for y in xrange(self.h):
            for x in xrange(self.w):
                self.cells[y][x].state = 1
                self.cells[y][x].toggle()

    def randomize(self):
        self.clear()
        for y in xrange(self.h):
            for x in xrange(self.w):
                if Math.random() < 0.2:
                    self.cells[y][x].toggle()
